package com.gitee.hermer.engine.jars.dependent.activemq.core.pool;

import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Session;

import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQSession;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import com.gitee.hermer.boot.jee.commons.collection.StringCache;
import com.gitee.hermer.boot.jee.commons.log.Logger;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.engine.jars.dependent.activemq.config.ActiveMQProperties;
import com.gitee.hermer.engine.jars.dependent.activemq.core.ActiveMQContext;


public class ActiveMQSessionPoolFactory extends BasePooledObjectFactory<Session> implements DisposableBean,InitializingBean{
	private static Logger log = Logger.getLogger(ActiveMQSessionPoolFactory.class);
	GenericObjectPool<Session> pool = null;
	Connection connection = null;
	boolean initConnectionIsSucced = false;
	private String brokerURL;
	private int status = 0;
	private int weight = 10;

	ActiveMQSessionPoolFactory(){

	}
	
	
	public Connection getConnection() {
		return connection;
	}


	private ActiveMQProperties properties;


	public int getWeight()
	{
		return this.weight;
	}

	public void setWeight(int weight)
	{
		this.weight = weight;
	}



	public String getBrokerURL()
	{
		return this.brokerURL;
	}

	public int getStatus()
	{
		return this.status;
	}

	public void setStatus(int status)
	{
		this.status = status;
	}

	public ActiveMQSessionPoolFactory(ActiveMQProperties properties,String brokerURL, String weight)
	{
		this.properties = properties;
		this.brokerURL = new StringCache("failover:("+brokerURL+")?initialReconnectDelay=1000&maxReconnectDelay=30000").toString();
		if (!StringUtils.isEmpty(weight)) {
			this.weight = Integer.valueOf(this.weight).intValue();
		}
	}
	@Override
	public Session create()
			throws Exception
	{
		try
		{
			if ((!this.initConnectionIsSucced) && (!isFailoverMode())) {
				init();
			}
			if (!this.initConnectionIsSucced) {
				throw new Exception("init Connection fail");
			}
			if (this.connection == null) {
				throw new Exception("connection is null");
			}
			return this.connection.createSession(properties.getIsUseTransacted(), Session.AUTO_ACKNOWLEDGE);
		}
		catch (JMSException e)
		{
			log.error("jMS create session error", e);
			throw e;
		}
	}

	private boolean isFailoverMode()
	{
		if (this.brokerURL.indexOf("failover") > 0) {
			return true;
		}
		return false;
	}

	@Override
	public PooledObject<Session> wrap(Session session)
	{
		return new DefaultPooledObject(session);
	}

	@Override
	public void destroyObject(PooledObject<Session> p)
			throws Exception
	{
		if (p != null)
		{
			ActiveMQSession s = (ActiveMQSession)p.getObject();
			if (s != null) {
				s.close();
			}
		}
	}

	@Override
	public boolean validateObject(PooledObject<Session> p)
	{
		if (p != null)
		{
			ActiveMQSession s = (ActiveMQSession)p.getObject();
			if ((s == null) || (s.isClosed())) {
				return false;
			}
		}
		else
		{
			return false;
		}
		return true;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		init();
	}

	public ActiveMQSessionPoolFactory init()
	{
		if (this.pool != null) {
			this.pool.close();
		}
		GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
		poolConfig.setTestOnBorrow(true);
		poolConfig.setTestOnReturn(true);
		poolConfig.setMaxIdle(properties.getMaxIdle());
		poolConfig.setMaxTotal(properties.getMaxTotal());
		poolConfig.setMinIdle(properties.getMinIdle());
		this.pool = new GenericObjectPool(this, poolConfig);
		ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(
				this.brokerURL);
		factory.setConsumerFailoverRedeliveryWaitPeriod(10000L);
		factory.setTrustAllPackages(true);
		try
		{
			synchronized (ActiveMQSessionPoolFactory.class)
			{
				if (this.connection != null) {
					this.connection.close();
				}
				this.connection = factory.createConnection();
				if ((properties.getIsUseTransacted()) && 
						((this.connection instanceof ActiveMQConnection))) {
					((ActiveMQConnection)this.connection).setAlwaysSyncSend(true);
				}
				this.connection.start();
			}
			this.initConnectionIsSucced = true;
		}
		catch (JMSException e)
		{
			log.error("init jMS error", e);
			this.initConnectionIsSucced = false;
		}
		return this;
	}

	public Session getMQSession(String key)
	{
		Session session = null;
		try
		{
			session = this.pool.borrowObject();
			if (session == null)
			{
				if (this.connection == null) {
					return session;
				}
				int ii = 0;
				do
				{
					ii++;
					session = this.pool.borrowObject();
					if (session != null) {
						return session;
					}
				} while (ii < 3);
				return session;
			}
		}
		catch (Exception e)
		{
			log.error("jMS getSession error", e);
		}
		return session;
	}
	@Deprecated
	public boolean monitor()
	{
		if ((this.connection != null && this.connection instanceof ActiveMQConnection)) {
			try{
				((ActiveMQConnection)this.connection).getClientID();
			}catch (Exception e) {
				log.warn("monitor getConnection is fail,url=" + 
						properties.getBrokerURL());
				//				this.connection = null;
				//				this.initConnectionIsSucced = false;
				//				return false;
			}
		}
		return true;
	}

	public void returnSession(Session session)
	{
		try
		{
			if (session != null) {
				this.pool.returnObject(session);
			}
		}
		catch (Exception e)
		{
			log.error("jMS returnSession  error", e);
		}
	}
	@Override
	public void destroy()
	{
		try {
			if(connection != null){
				connection.close();
				connection = null;
			}
		} catch (JMSException e) {

		}
		this.pool.close();
	}

	public Session getOneSession()
	{
		return getMQSession(null);
	}


}
